package cn.qingyun.gis.modules.baogan.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.qingyun.gis.exception.CommonException;
import cn.qingyun.gis.modules.baogan.dto.PolDto;
import cn.qingyun.gis.modules.baogan.dto.VisitTotalDto;
import cn.qingyun.gis.modules.baogan.entity.BaoganTeam;
import cn.qingyun.gis.modules.baogan.entity.CrmStaff;
import cn.qingyun.gis.modules.baogan.entity.MicroStreetData;
import cn.qingyun.gis.modules.baogan.entity.MicrogridCareRecordEntity;
import cn.qingyun.gis.modules.baogan.mapper.BaoganTeamMapper;
import cn.qingyun.gis.modules.baogan.mapper.CrmStaffMapper;
import cn.qingyun.gis.modules.baogan.mapper.MicroStreetDataMapper;
import cn.qingyun.gis.modules.baogan.mapper.MicrogridCareRecordMapper;
import cn.qingyun.gis.modules.baogan.service.MicroStreetDataService;
import cn.qingyun.gis.modules.baogan.service.MicrogridCareRecordService;
import cn.qingyun.gis.modules.baogan.vo.request.*;
import cn.qingyun.gis.modules.baogan.vo.response.*;
import cn.qingyun.gis.modules.scenes.entity.UniAddrRegion;
import cn.qingyun.gis.modules.scenes.service.UniAddrRegionService;
import cn.qingyun.gis.modules.scenes.mapper.PoiScenarioMapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
@DS("scenes_offensive")
public class MicroStreetDataServiceImpl extends ServiceImpl<MicroStreetDataMapper, MicroStreetData> implements MicroStreetDataService {
    @Resource
    private MicroStreetDataMapper streetDataMapper;
    @Resource
    private BaoganTeamMapper baoganTeamMapper;
    @Resource
    private MicrogridCareRecordMapper microgridCareRecordMapper;
    @Resource
    private CrmStaffMapper crmStaffMapper;
    @Resource
    private UniAddrRegionService uniAddrRegionService;
    @Resource
    private PoiScenarioMapper poiScenarioMapper;
    @Resource
    private MicrogridCareRecordService careRecordService;

    @Override
    public PolygonDetailRes selectStreetDetail(String microGridCode, String id) {
        // 异步获取建筑数量
        CompletableFuture<Integer> buildingTotalFuture = CompletableFuture.supplyAsync(() ->
                streetDataMapper.selectStreetBuildingTotal(microGridCode, id))
                .exceptionally(e -> {
                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                    return 0;
                });

        // 异步获取企业数量
        CompletableFuture<Integer> enterpriseTotalFuture = CompletableFuture.supplyAsync(() ->
                streetDataMapper.selectStreetEnterpriseTotal(microGridCode, id))
                .exceptionally(e -> {
                    log.error("异步获取企业数量: {}", e.getMessage(), e);
                    return 0;
                });

        // 异步获取未随访和已随访数量
        CompletableFuture<VisitTotalDto> visitTotalFuture = CompletableFuture.supplyAsync(() ->
                streetDataMapper.selectStreetVisitTotal(microGridCode, id))
                .exceptionally(e -> {
                    log.error("异步获取未随访和已随访数量: {}", e.getMessage(), e);
                    return new VisitTotalDto(0, 0);
                });
        //异步查询看管人员
        CompletableFuture<List<MicrogridCareRecordEntity>> custodiansFuture = CompletableFuture.supplyAsync(() ->
                microgridCareRecordMapper.selectStreetCustodians(microGridCode, id))
                .exceptionally(e -> {
                    log.error("异步查询看管人员: {}", e.getMessage(), e);
                    return Collections.emptyList();
                });

        //异步查询变更面数据
        CompletableFuture<PolDto> logFuture = CompletableFuture.supplyAsync(() ->
                microgridCareRecordMapper.selectWKTLogData(microGridCode,id))
                .exceptionally(e -> {
                    log.error("异步查询变更面数据: {}", e.getMessage(), e);
                    return new PolDto();
                });
        //查询微网格是否已经被看管划分
        CompletableFuture<Integer> cardFlagFuture = CompletableFuture.supplyAsync(() ->
                        microgridCareRecordMapper.slectMicroCareFlag(microGridCode,id))
                .exceptionally(e -> {
                    log.error("查询微网格是否已经被看管划分: {}", e.getMessage(), e);
                    return 0;
                });

        // 当所有异步操作都完成时，设置结果
        CompletableFuture<PolygonDetailRes> resultFuture = CompletableFuture.allOf(buildingTotalFuture, enterpriseTotalFuture, visitTotalFuture,custodiansFuture,logFuture,cardFlagFuture)
                .thenApply((Void) -> {
                    PolygonDetailRes res = streetDataMapper.selectStreetDetail(microGridCode, id);
                    if (ObjectUtil.isNull(res)){
                        res = new PolygonDetailRes();
                    }

                    Integer buildingTotal = buildingTotalFuture.join();
                    Integer enterpriseTotal = enterpriseTotalFuture.join();
                    VisitTotalDto visitTotalDto = visitTotalFuture.join();
                    List<MicrogridCareRecordEntity> careList = custodiansFuture.join();
                    PolDto polDto = logFuture.join();
                    Integer careFlag = cardFlagFuture.join();

                    if (ObjectUtil.isNotNull(polDto)){
                        res.setPolData(polDto);
                    }
                    if (ObjectUtil.isNotNull(buildingTotal)) {
                        res.setBuildingTotal(buildingTotal);
                    }
                    if (ObjectUtil.isNotNull(enterpriseTotal)) {
                        res.setEnterpriseTotal(enterpriseTotal);
                    }
                    if (ObjectUtil.isNotNull(visitTotalDto)) {
                        res.setNoVisitedTotal(visitTotalDto.getNoVisitedTotal());
                    }
                    if (ObjectUtil.isNotNull(visitTotalDto)) {
                        res.setVisitedTotal(visitTotalDto.getVisitedTotal());
                    }
                    if (ObjectUtil.isNotNull(careList)) {
                        res.setCustodians(careList);
                    }
                    if (ObjectUtil.isNotNull(careFlag)){
                        res.setMicroCareFlag(careFlag);
                    }
                    return res;
                });
        try {
            return resultFuture.get();
        } catch (Exception e) {
            throw new RuntimeException("异步编排查询微网格详情错误={}", e);
        }
    }

    @Override
    public List<TeamItemVo> listTeam(GridCodeAndKeyListRequest request) {
        List<TeamItemVo> list = baoganTeamMapper.listTeamByGridAndKey(request.getGridCode(), request.getKey());
        if(CollUtil.isNotEmpty(list)){
            //查询每一个队伍下的成员列表
            list.forEach(team->{
                LambdaQueryWrapper<BaoganTeam> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper
                        .eq(BaoganTeam::getTeamId, team.getTeamId())
                        .and(StringUtil.isNotBlank(request.getKey()),wq->wq.like(BaoganTeam::getUserName,request.getKey()).or().like(BaoganTeam::getUserEmployeeNumber,request.getKey()));
                List<BaoganTeam> baoganTeams = baoganTeamMapper.selectList(queryWrapper);
                List<TeamMemberItemVo> memberItemVoList = baoganTeams.stream().map(item -> {
                    TeamMemberItemVo teamMemberItemVo = new TeamMemberItemVo();
                    BeanUtils.copyProperties(item, teamMemberItemVo);
                    return teamMemberItemVo;
                }).collect(Collectors.toList());
                team.setMemberList(memberItemVoList);
            });
        }
        return list;
    }

    @Override
    public Set<ChannelItemVo> listChannel(GridCodeAndKeyListRequest request) {
        LambdaQueryWrapper<CrmStaff> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(CrmStaff::getGridCode,request.getGridCode())
                .and(StringUtil.isNotBlank(request.getKey()),eq->eq.like(CrmStaff::getChannelCode,
                        request.getKey())).or().like(CrmStaff::getChannelName,request.getKey());
        List<CrmStaff> crmStaffs = crmStaffMapper.selectList(queryWrapper);
        Set<ChannelItemVo> resultList = crmStaffs.stream().map(item -> {
            ChannelItemVo channelItemVo = new ChannelItemVo();
            BeanUtils.copyProperties(item, channelItemVo);
            return channelItemVo;
        }).collect(Collectors.toSet());
        return resultList;
    }

    @Override
    public StreetBaseResponse getWatchDivisionBaseInfo(IdRequest request) {
        StreetBaseResponse streetBaseResponse = new StreetBaseResponse();
        //计算面积
        Double area = streetDataMapper.getAreaById(request.getId());
        streetBaseResponse.setArea(area);
        //查询建筑数
        Integer buildCount = streetDataMapper.getBuildCount(request.getId());
        streetBaseResponse.setBuildCount(buildCount);
        //查询企业数
        Integer companyCount = streetDataMapper.getCompanyCount(request.getId());
        streetBaseResponse.setCompanyCount(companyCount);

        return streetBaseResponse;
    }

    @Override
    public List<EnterpriseResponse> selectEnterpriseList(String id) {
        return microgridCareRecordMapper.selectEnterpriseList(id);
    }

    /**
     * 查询绘制面中的建筑数、企业数
     *
     * @param request
     * @return
     */
    @Override
    public AoiBaseInfoVo getAoiBaseInfo(AoiBaseInfoGetRequest request) {
        AoiBaseInfoVo aoiBaseInfoVo = new AoiBaseInfoVo();
        //查询建筑数
        int buildCount = poiScenarioMapper.getAoiBaseInfo(request);
        aoiBaseInfoVo.setBuildCount(buildCount);
        //查询企业数
        int companyCount = poiScenarioMapper.getAoiBaseInfo(request);
        aoiBaseInfoVo.setCompanyCount(companyCount);
        return aoiBaseInfoVo;
    }

    @Override
    public List<MicroStreetAuditLogResp> selectAuditData(PendingAuditRequest request) {
        log.debug("查询待审核面数据列表入参{}",request);
        Integer level = uniAddrRegionService.selectLevel(request.getCode());
        List<MicroStreetAuditLogResp> list = streetDataMapper.selectAuditData(request, level);
        log.debug("待审核面数据列表大小{}",list);
        return list;
    }

    @Override
    public List<PerimeterDataResp> selectPerimeterData(PerimeterRequest request) {
        log.debug("开启周边入参{}",request);
        //根据中心点5千米范围的面与地市相交，取地市编码集合
        QueryWrapper<UniAddrRegion> wrapper = new QueryWrapper<>();
        wrapper.select("id","code","name","level","ST_AsText(wkt) as wkt").eq("code",request.getCode()).ne("state",-1);
        UniAddrRegion uniAddrRegion = uniAddrRegionService.getBaseMapper().selectOne(wrapper);
        if (uniAddrRegion==null || StringUtils.isEmpty(uniAddrRegion.getCode()) ||uniAddrRegion.getLevel()==null){
            throw new CommonException("未找到对应的区划数据！");
        }
        ArrayList<PerimeterDataResp> list = Lists.newArrayList();
        //1.先查面数据
        List<PerimeterDataResp> perimeterStreetData = streetDataMapper.selectPerimeterStreetData(request,uniAddrRegion.getCode(),uniAddrRegion.getLevel());
        list.addAll(perimeterStreetData);
        //2.再查点数据
        List<PerimeterDataResp> perimeterPoiData = poiScenarioMapper.selectPerimeterPoiData(request, uniAddrRegion.getCode(),uniAddrRegion.getLevel());
        list.addAll(perimeterPoiData);
        log.debug("周边返回的集合大小{}",list.size());
        return list;
    }

    @Override
    public MGridDetailRes getReviewingDetail(String microGridCode, String id) {//面id
        //异步查询面详情
        CompletableFuture<MicroStreetData> streetFuture = CompletableFuture.supplyAsync(() ->
                streetDataMapper.selectOneById(microGridCode,id))
                .exceptionally(e -> {
                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                    return new MicroStreetData();
                });

        // 当所有异步操作都完成时，设置结果
        CompletableFuture<MGridDetailRes> resultFuture = CompletableFuture.allOf(streetFuture)
                .thenApply((Void) -> {
                    MicroStreetData streetData = streetFuture.join();
                    MGridDetailRes res = new MGridDetailRes();
                    if (ObjectUtil.isNotNull(streetData)){
                        BeanUtils.copyProperties(streetData, res);
                    }
                    if (ObjectUtil.isNotNull(streetData)){
                        //异步查询企业总数
                        CompletableFuture<Integer> enterpriseTotalFuture = CompletableFuture.supplyAsync(() ->
                                streetDataMapper.selectStreetEnterpriseTotal(streetData.getMicroGridCode(), id))
                                .exceptionally(e -> {
                                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                                    return 0;
                                });
                        //异步查询建筑总数
                        CompletableFuture<Integer> buildingTotalFuture = CompletableFuture.supplyAsync(() ->
                                streetDataMapper.selectStreetBuildingTotal(streetData.getMicroGridCode(), id))
                                .exceptionally(e -> {
                                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                                    return 0;
                                });
                        //异步查询未随访和已随访数量
                        CompletableFuture<VisitTotalDto> visitTotalFuture = CompletableFuture.supplyAsync(() ->
                                streetDataMapper.selectStreetVisitTotal(streetData.getMicroGridCode(), id))
                                .exceptionally(e -> {
                                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                                    return new VisitTotalDto(0, 0);
                                });
                        //异步查询看管人员
                        CompletableFuture<List<MicrogridCareRecordEntity>> custodiansFuture = CompletableFuture.supplyAsync(() ->
                                microgridCareRecordMapper.selectMGCustodians(streetData.getMicroGridCode(), id))
                                .exceptionally(e -> {
                                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                                    return Collections.emptyList();
                                });
                        //异步查询原始wkt
                        CompletableFuture<PolDto> wktFuture = CompletableFuture.supplyAsync(() ->
                                careRecordService.selectWKTLogData(streetData.getMicroGridCode(), id))
                                .exceptionally(e -> {
                                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                                    return new PolDto();
                                });

                        res.setEnterpriseTotal(enterpriseTotalFuture.join());//企业总数
                        res.setBuildingTotal(buildingTotalFuture.join());//建筑总数
                        res.setNoVisitedTotal(visitTotalFuture.join().getNoVisitedTotal());//未随访总数
                        res.setVisitedTotal(visitTotalFuture.join().getVisitedTotal());//已随访总数
                        res.setCustodians(custodiansFuture.join());//看管人员

                        return res;
                    }else {
                        throw new CommonException("未找到对应的微网格数据！");
                    }
                });
        try {
            return resultFuture.get();
        } catch (Exception e) {
            throw new RuntimeException("异步编排查询微网格详情错误={}", e);
        }
    }

    @Override
    public boolean addBoundary(MicroStreetData data) {
        return this.baseMapper.addBoundary(data);
    }

    @Override
    public void updateWKT(MicroStreetData streetData) {
        this.baseMapper.updateWkt(streetData);
    }

    @Override
    public MicroStreetData selectOneById(String id) {
        return this.baseMapper.MicroStreetData(id);
    }

    @Override
    public boolean saveBoundary(MicroStreetData data) {
        return this.baseMapper.saveBoundary(data);
    }
}
